package zjut.raymond.witdemo.algorithm;

import Jama.CholeskyDecomposition;
import Jama.Matrix;

public class JamaUtils {
    public static void dispMatrix(double[][] m) {
        for (int i = 0; i < m.length; i++) {
            for (int j = 0; j < m[i].length; j++) {
                System.out.printf("%-15.2f", m[i][j]);
            }
            System.out.println();
        }
    }

    public static double[][] matrixAdd(double[][] m, double[][] n) {

        Matrix A = new Matrix(m);
        Matrix B = new Matrix(n);
        return A.plus(B).getArray();

    }

    public static double[][] matrixSub(double[][] m, double[][] n) {
        Matrix A = new Matrix(m);
        Matrix B = new Matrix(n);
        return A.minus(B).getArray();
    }

    //矩阵乘法
    public static double[][] matrixMult(double[][] m, double[][] n) {
        Matrix A = new Matrix(m);
        Matrix B = new Matrix(n);
        A = A.times(B);
        return A.getArray();
    }

    public static double[][] matrixMultiply(double[][] m, double k) {
        Matrix A = new Matrix(m);
        return A.times(k).getArray();
    }

    // 求矩阵的逆
    public static double[][] matrixInverse(double[][] m) {
        Matrix A = new Matrix(m);
        return A.inverse().getArray();
    }

    //矩阵转置
    public static double[][] matrixTranspose(double[][] m) {

        Matrix A = new Matrix(m);
        return A.transpose().getArray();

    }

    //求特征值
    public static double[][] matrixEigD(double[][] m) {

        Matrix A = new Matrix(m);
        return A.eig().getD().getArray();

    }

    public static double[][] matrixEigV(double[][] m) {

        Matrix A = new Matrix(m);
        return A.eig().getV().getArray();

    }

    public static double matrixDet(double[][] m) {

        Matrix A = new Matrix(m);
        return A.det();

    }

    //矩阵的秩
    public static double matrixRank(double[][] m) {

        Matrix A = new Matrix(m);
        return A.rank();

    }

    //矩阵列数
    public static int getMatrixColumn(double[][] m) {
        Matrix A = new Matrix(m);
        return A.getColumnDimension();
    }

    //矩阵行数
    public static int getMatrixRow(double[][] m) {
        Matrix A = new Matrix(m);
        return A.getRowDimension();
    }

    public static double[][] matrixSolve(double[][] m, double[][] n) {
        Matrix A = new Matrix(m);
        Matrix B = new Matrix(n);
        A = A.solve(B);
        return A.getArray();
    }

    public static double[][] matrixSolveTran(double[][] m, double[][] n) {
        Matrix A = new Matrix(m);
        Matrix B = new Matrix(n);
        A = A.solveTranspose(B);
        return A.getArray();
    }

    public static double[] TwotoOne(double[][] two) {
        double[] one;
        int len = two.length * two.length;
        one = new double[len];
        int index = 0;
        for (int i = 0; i < two.length; i++) {
            for (int j = 0; j < two[i].length; j++) {
                one[index++] = two[i][j];
            }
        }
        return one;
    }

    public static double[][] OneToTwo(double[] one) {

        return new Matrix(one, (int) Math.sqrt(one.length)).transpose().getArray();
    }

    public static double[][] getResult(double[][] m, double[][] n, int flag) {

        double[][] result = m;

        switch (flag) {
            case 1:
                result = JamaUtils.matrixAdd(m, n);
                break;
            case 2:
                result = JamaUtils.matrixSub(m, n);
                break;
            case 3:
                result = JamaUtils.matrixMult(m, n);
                break;
            case 4:
                result = JamaUtils.matrixSolve(m, n);
                break;
            case 5:
                result = JamaUtils.matrixSolveTran(m, n);
                break;
        }
        return result;
    }

    public static StringBuilder output(double[] c) {
        StringBuilder sb = new StringBuilder();
        int row = (int) Math.sqrt(c.length);
        for (int i = 0; i < c.length; i++) {
            if ((i + 1) % row == 0) {
                sb.append(String.format("%.3f", c[i]) + "\n");
            } else {
                sb.append(String.format("%.3f", c[i]) + ",  ");
            }
        }
        return sb;
    }

    public static StringBuilder output(double[][] cc) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < cc.length; i++) {
            for (int j = 0; j < cc[i].length; j++) {
                sb.append(String.format("%.3f", cc[i][j]) + "   ");
            }
            sb.append("\n");
        }
        return sb;
    }

    public static double[][] OneToTwo(double[] one, int row, int column) {
        double[][] m = new double[row][column];
        int index = 0;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                m[i][j] = one[index];
                index++;
            }
        }
        return m;
    }

    public static double[] StrToNum(String a) {

        String[] b = a.replaceAll("\n", ",").split(",");
        double[] num = new double[b.length];
        for (int i = 0; i < b.length; i++) {
            num[i] = Double.parseDouble(b[i]);
        }
        return num;
    }

    public static double[][] MatrixCholesky(double[][] m) {
        Matrix A = new Matrix(m);
        CholeskyDecomposition choleskyDecomposition = A.chol();
        return choleskyDecomposition.getL().getArray();
    }

    public static double[][] getColumnByIndex(double[][] m, int index) {
        if (index < 0 || index > JamaUtils.getMatrixColumn(m)) return null;

        double[][] res = new double[JamaUtils.getMatrixRow(m)][1];
        for (int i = 0; i < res.length; i++) {
            res[i][0] = m[i][index];
        }
        return res;
    }

    public static double[][] InsertMatrixByIndex(double[][] m, double[][] n, int index) {
        if (index < 0 || index > JamaUtils.getMatrixColumn(m) || JamaUtils.getMatrixRow(n) != JamaUtils.getMatrixRow(m) || JamaUtils.getMatrixColumn(n) != 1) return m;
        for (int i = 0; i < JamaUtils.getMatrixRow(m); i++) {
            m[i][index] = n[i][0];
        }
        return m;
    }
}
